#!/usr/bin/env python
# -*- coding: utf-8 -*-


import datetime
from . import command
from .message import Message
from .uart import Txd, Rxd

from .tools import singleton
from .tools import to_hex_list
from .tools import Timer2
from . import tools

import time
import logging
_logger = logging.getLogger(__name__)


@singleton
class Control(object):
    def __init__(self, dev=None, host=None, odoo=None, db=None, sensors=None):
        # odoo 是 服务器
        # db 是 本地数据库
        self.odoo = odoo
        self.db = db

        self.host = host

        # 从机里 有 code, 读取后 写在自己这里
        self.gatewate_code = ''

        # 启动 串口接收线程, 创建消息处理对象, 参数: 回调函数
        # 启动 串口接收线程, 参数: 串口号,  被主机调用还是模拟从机调用, 消息处理对象,
        self.rxd = Rxd(dev=dev, host=host, msg=Message(self.get_command))
        time.sleep(0.5)
        # 启动 串口发送线程, 参数: 串口号,  被主机调用还是模拟从机调用,
        self.txd = Txd(dev=dev, host=host)
        time.sleep(0.5)

        # 仅仅 作为从机, 模拟应答数据时 , 需要 sensors
        self.sensors = sensors

    def get_command(self, cmd_word, data):
        # 串口接收回调函数,
        # 参数:
        # 命令字 int,
        # 数据 list[ hex ]

        # print ('Control, get_command: cmd, data:', self.host, cmd_word, data)

        # 解析 命令字及数据
        cmd = command.get_commond(self.host, cmd_word, data)
        if not cmd:
            # 非法指令
            # _logger.info( 'rxd, cmd=%s, data=%s' %(cmd.Cmd_word_string, cmd.data))

            return None

        # _logger.info('rxd ++++++++++++++++++++++ from: ')
        # _logger.info('cmd=%s, data=%s' % (cmd.Cmd_word_string, cmd.data))

        # print ('Control, rxd, cmd, : :', self.host, cmd.Cmd_word_string, cmd.data)

        # 如果需要应答, 获取应答的内容, 并发送
        ack_ret = cmd.ack(sensors=self.sensors)
        if ack_ret:
            _logger.info('rxd ++++++++++++++++++++++ from: ')
            _logger.info('cmd=%s, data=%s' % (cmd.Cmd_word_string, cmd.data))
            _logger.info('need to ack')

            if len(ack_ret) == 2:
                ack_word, ack_data = ack_ret
                _logger.info('rxd, ack， cmd=%s, %s, data=%s' %
                             (cmd.Cmd_word_string, hex(ack_word), to_hex_list(ack_data)))
                # print('ack_cmd_word, ack_cmd_data', ack_word, ack_data)
                self.txd.txd_data(ack_word, ack_data)

            elif len(ack_ret) >= 2:
                print('>2', ack_ret)
                ack_word = ack_ret[0]
                ack_datas = ack_ret[1:]
                for ack_data in ack_datas:
                    _logger.info('rxd, ack， cmd=%s, %s, data=%s' %
                                 (cmd.Cmd_word_string, ack_word, ack_data))
                    # print('ack_cmd_word, ack_cmd_data', ack_word, ack_data)
                    self.txd.txd_data(ack_word, ack_data)

        else:
            pass
            # _logger.info('rxd ++++++++++++++++++++++ from: ')
            # _logger.info('cmd=%s, data=%s' % (cmd.Cmd_word_string, cmd.data))
            # _logger.info('need not to ack')

            # _logger.info('rxd, no ack， cmd=%s, data=%s' %
            #              (cmd.Cmd_word_string, cmd.data))

        # 后续处理, 本地存储, 上传服务器
        cmd.next(self)

        return cmd

    def send_ready(self, now_timestamp):
        # 读取 gateway code
        # 1 发送命令, 2 等待接收到命令

        cmd = command.CmdSendReady('host', 'down', now_timestamp=now_timestamp)
        loop_num = 3
        code = None
        while loop_num and not code:
            loop_num = loop_num - 1
            # _logger.info('wait CmdSendReady for %s times.' % loop_num)
            code = self.send_ready_one(cmd)
            time.sleep(1)

        return code

    def send_ready_one(self, cmd):
        # cmd_word_and_data = cmd.data
        # print('host, down,dev_code, cmd_word_data:',dev_code, cmd_word_and_data)
        cmd_word, data = cmd.data
        # print('now_timestamp, cmd_word, data:', now_timestamp, cmd_word, data)
        # logger.info('odoo now_timestamp is: %s' % now_timestamp)
        _logger.debug('--cmd_word=%s, data=%s' %
                      (hex(cmd_word), to_hex_list(data)))

        self.txd.txd_data(cmd_word, data)

        timer = Timer2(10)
        while not timer.timeout and not cmd.rxd_gatewate_code:
            time.sleep(0.5)

        timer.cancel()
        if cmd.rxd_gatewate_code:
            self.gatewate_code = cmd.rxd_gatewate_code
            # _logger.info('++++ get gatewate_code= %s', cmd.rxd_gatewate_code)
        else:
            _logger.info('read gatewate_code, no ack')

        return cmd.rxd_gatewate_code

    def sensor_loc_to_odoo(self):
        # _logger.info('sensor_loc_to_odoo')
        command.sensor_loc_to_odoo(self.odoo, self.db)

    #
    #
    #
    def send_net(self, odoo_status):
        # 发送网络状态
        cmd = command.CmdSendNet('host', 'down', odoo_status=odoo_status)
        cmd_word, data = cmd.data
        _logger.info('send ---------------------------- to: ')
        _logger.info('cmd_word=%s, data=%s' %
                     (hex(cmd_word), to_hex_list(data)))

        self.txd.txd_data(cmd_word, data)
        time.sleep(1)
        self.txd.txd_data(cmd_word, data)
        time.sleep(1)
        _logger.info('send net ok')

    def send_wakeup(self):
        cmd = command.CmdWakeup('host', 'down')
        cmd_word, data = cmd.data

        _logger.info('send ---------------------------- to: ')
        _logger.info('cmd_word=%s, data=%s' %
                     (hex(cmd_word), to_hex_list(data)))

        # print('shutdown_me, cmd_word, data:', cmd_word, data)
        self.txd.txd_data(cmd_word, data)
        time.sleep(1)
        self.txd.txd_data(cmd_word, data)
        time.sleep(1)
        _logger.info('send wakeup ok')

    def read_device(self):
        devices = []

        if self.odoo.session_id:
            # 从服务器上读取 设备列表
            domain = [('gateway_id.code', '=', self.gatewate_code)]
            devices = self.odoo.env['iot.device'].search_read(
                domain, fields=['code'])
            # print('devices from odoo,1,:', devices)
            csv_file_name = tools.get_arg('--data')
            tools.set_csv_data(csv_file_name, devices)
            devices = [dev['code'] for dev in devices]
            # print('devices from odoo,2:', devices)
            pass

        else:
            # 读取配置文件, 获得 有哪些 devices 用来循环 读取
            devices2 = tools.get_csv_data()
            devices = [dev['code'] for dev in devices2]

        # _logger.info('my devices is: %s' % devices)
        devices = [int(dev, 16) for dev in devices]
        loop_count = 2
        for loop in range(loop_count):
            for dev_code in devices:
                _logger.debug('loop=%s of %s, dev code=%s of %s' %
                              (loop, loop_count,  dev_code, devices))
                ret = self.read_device_one_one(dev_code, devices)
                if ret:
                    time.sleep(2)

    def read_device_one_one(self, dev_code, devices):

        # _logger.info('send to call all devices.')
        cmd = command.CmdReadDevice(
            'host', 'down', code=dev_code, devices=devices)
        cmd_word, data = cmd.data
        self.txd.txd_data(cmd_word, data)

        # print(' timer 10 is atart')
        timer = Timer2(12)
        while not timer.timeout and not cmd.rxd_data.get(dev_code):
            time.sleep(0.5)

        timer.cancel()
        if cmd.rxd_data.get(dev_code):
            _logger.debug('GET read %s device= %s' %
                          (dev_code, cmd.rxd_data.get(dev_code)))
            del cmd.rxd_data[dev_code]
            return True
        else:
            # del cmd.rxd_data[dev_code]
            _logger.warning('GET read %s device , no ack' % dev_code)
            _logger.warning('cmd.rxd_data: %s' % cmd.rxd_data)
            return False

    def shutdown_me(self, now_timestamp):

        # 从服务器同步时间
        # now_timestamp = self.odoo.get_now()
        _logger.debug('send shutdown with timestamp= %s' % now_timestamp)

        cmd = command.CmdSendShutDown(
            'host', 'down', now_timestamp=now_timestamp)

        # cmd_word_and_data = cmd.data
        # print('host, down,dev_code, cmd_word_data:',dev_code, cmd_word_and_data)
        cmd_word, data = cmd.data

        _logger.debug('---cmd_word=%s, data=%s' %
                      (hex(cmd_word), to_hex_list(data)))

        # print('shutdown_me, cmd_word, data:', cmd_word, data)
        self.txd.txd_data(cmd_word, data)

        #
        _logger.debug('wait slave ack, so i can shut down')
        wait_num = 10
        while wait_num and not cmd.shutdown:
            wait_num = wait_num - 1
            # _logger.info('check rxd state_num=%s' % self.rxd.state_num)
            time.sleep(1)

        # _logger.info('check rxd state_num=%s, wait_num=%s' %
        #              (self.rxd.state_num, wait_num))
        return cmd.shutdown
